package me.derekng.facedetection;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
//import org.opencv.highgui.Highgui;  // for opencv opencv2.4.13
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;


/**
 * 人脸检测
 * Created by wudeh on 2017/4/15.
 */
public class FaceDetector {

    public static void main(String[] args) {

        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        System.out.println("\n启动 FaceDetector");

        // 加载原图像
        String srcFile = "source.png";
        Mat source = Imgcodecs.imread(srcFile);

        // 加载需要识别的人脸模板
        String templateFile = "template.png";
        Mat template=Imgcodecs.imread(templateFile);

        // 对人脸进行检测
        doDetect(source);

        // 根据模板进行人脸匹配
        doMatch(source, template);

        // 输出检测和识别的结果
        String filename = "ouput.png";
        System.out.println(String.format("Writing %s", filename));
        Imgcodecs.imwrite(filename, source);
    }

    /**
     * 人脸检测
     * @param source 原图像
     */
    private static void doDetect(Mat source) {
        // 加载特征分类器
        String xmlfile = "haarcascade_frontalface_alt.xml";
        CascadeClassifier faceDetector
                = new CascadeClassifier(xmlfile);
        boolean isLoad = faceDetector.load(xmlfile);
        if(isLoad) {
            MatOfRect faceDetections = new MatOfRect();
            // 开始识别
            faceDetector.detectMultiScale(source, faceDetections);

            System.out.println(String.format("检测到 %s 张人脸", faceDetections.toArray().length));

            // 对检测到的人脸进行标识
            for (Rect rect : faceDetections.toArray()) {
                Imgproc.rectangle(source, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height),
                        new Scalar(0, 0, 255), Core.FONT_HERSHEY_PLAIN);
            }
        }else{
            System.out.println("加载特征分类器失败！");
        }
    }

    /**
     * 人脸匹配
     * @param source  原图像
     * @param template 模板图像
     */
    private static void doMatch(Mat source, Mat template) {

        Mat outputImage=new Mat();
        int machMethod=Imgproc.TM_CCOEFF;

        // 开始匹配
        Imgproc.matchTemplate(source, template, outputImage, machMethod);

        // 取得匹配的坐标
        Core.MinMaxLocResult mmr = Core.minMaxLoc(outputImage);
        Point matchLoc=mmr.maxLoc;

        // 在匹配到坐标位置绘制"MATCHED"文字标识
        Imgproc.rectangle(source, matchLoc, new Point(matchLoc.x + template.cols(),
                matchLoc.y + template.rows()), new Scalar(0, 255, 0), Core.FONT_HERSHEY_COMPLEX);
        Imgproc.putText(source, "MATCHED", new Point(matchLoc.x ,
                matchLoc.y-10), Core.FONT_HERSHEY_COMPLEX, 1.0, new Scalar(0, 255, 0));
    }
}
